package com.example.codegeneratordemo.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.DbUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.simple.SimpleDataSource;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ClassPathResource;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

@Slf4j
public class CodeGenerator {

    private static final String TABLE = "sys_user";
    private static final String PACKAGE_NAME = "com.example.codegeneratordemo";
    private static final String AUTHOR = "小熊";
    private static final String VUE_CODE_PATH = "C:\\Users\\Administrator.DESKTOP-B173SQA\\Desktop\\codeGenerator-vue\\";

    // 不需要改
    private static final String PROJECT_PATH = System.getProperty("user.dir");
    public static final String MAPPER_XML_PATH = "/src/main/resources/mapper/";
    public static final String JAVA_CODE_PATH = "/src/main/java/";

    // 格式化代码
    private static final String SPACE8 = "        ";

    public static void main(String[] args) {

//        generateJava(TABLE);

        generateVue(TABLE);
    }

    private static void generateVue (String tableName) {

        List<TableColumn> tableColumns = getTableColumns(tableName);

        // 4 读取模板，生成代码
        // String vueTemplate = ResourceUtil.readStr("templates/vue.template", StandardCharsets.UTF_8);
        String vueTemplate = ResourceUtil.readUtf8Str("templates/vue.template");
        // System.out.println(vueTemplate);

        // 封装模板的代码
        // 把 map 作为一个模板 替换符
        Map<String, String> map = new HashMap<>();
        map.put("lowerEntity", getLowerEntity(tableName));      // 接口前缀

        String vueTableBody = getVueTableBody(tableColumns);
        map.put("tableBody", vueTableBody);

        String vueFormBody = getVueFormBody(tableColumns);
        map.put("formBody", vueFormBody);

        // 生成页面代码
        // 把 map 中数据 传到 vueTemplate 中
        // vuePage是替换字符串模板后的内容
        String vuePage = StrUtil.format(vueTemplate, map);

//        // 写文件
//        //  "D:\\IdeaProjects\\partner-manager\s\rc\\views"  是你vue工程文件的目录
//        FileUtil.writeUtf8String(vuePage, "C:\\Users\\Administrator.DESKTOP-B173SQA\\Desktop\\codeGenerator-vue\\"+ tableName + ".vue");
//        System.out.println("vue文件生成完成！！！");

        String entity = getEntity(tableName);
        FileUtil.writeUtf8String(vuePage, VUE_CODE_PATH + entity + ".vue");
        log.debug("==========================" + entity + ".vue文件生成完成！！！==========================");

    }
    private static List<TableColumn> getTableColumns(String tableName) {
        // 1.获取数据库连接的信息
        DBProp dbProp = getDBProp();

        // 2.连接数据库
        DataSource dataSource = new SimpleDataSource( "jdbc:mysql://localhost:3306/information_schema" , dbProp.getUsername(), dbProp.getPassword());
        Db db = DbUtil.use(dataSource);

        // 3.操作数据库

        // 拿到实际要生成代码的数据库的名称
        //  jdbc:mysql://localhost:3306/partner?serverTimezone=GMT%2b8
        //  url.indexOf("3306/") 到的是第一个位置所以要+5
        String url = dbProp.getUrl();
        String schema = url.substring(url.indexOf("3306/") + 5, url.indexOf("?"));

        // partner 可以不写死 因为后端没有传入partner,从.yml中的spring.datasource.url 中截取 得到 schema
        // columns 存储的是表字段集合
        List<TableColumn> tableColumnList = new ArrayList<>();
        try {
            List<Entity> columns = db.findAll(Entity.create("COLUMNS").set("TABLE_SCHEMA", schema).set("TABLE_NAME", tableName));
            // columns.forEach(System.out::println);
            // 封装结构化的表数据信息
            for (Entity entity : columns) {
                String columnName = entity.getStr("COLUMN_NAME");        // 字段名称
                String dataType = entity.getStr("DATA_TYPE");            // 数据类型
                String columnComment = entity.getStr("COLUMN_COMMENT");  // 数据注释
                TableColumn tableColumn = TableColumn.builder().columnName(columnName).dataType(dataType).columnComment(columnComment).build();
                tableColumnList.add(tableColumn);
            }
            // System.out.println(tableColumnList);
        }catch (SQLException e){
            throw new RuntimeException(e);
        }
        return tableColumnList;
    }

    private static String getVueTableBody(List<TableColumn> tableColumnList) {
        StringBuilder builder = new StringBuilder();
        for (TableColumn tableColumn : tableColumnList) {
            // id 有时候没写注释 需要特殊处理
            if (tableColumn.getColumnName().equalsIgnoreCase("id") && StrUtil.isBlank(tableColumn.getColumnComment())) {
                tableColumn.setColumnComment("编号");
            }
            // 排除 deleted create_time  update_time 这个无需关注的字段
            if (tableColumn.getColumnName().equalsIgnoreCase("deleted") || tableColumn.getColumnName().equalsIgnoreCase("create_time")
                    || tableColumn.getColumnName().equalsIgnoreCase("update_time")) {
                continue;
            }
            // 动态生成 注意添加换行
            String column = SPACE8 + "<el-table-column prop=\"" + tableColumn.getColumnName() + "\" label=\""
                           + tableColumn.getColumnComment() + "\"></el-table-column>\n";
            // 连接所有字符串
            builder.append(column);
        }
        return builder.toString();
    }

    private static String getVueFormBody(List<TableColumn> tableColumnList) {
        StringBuilder builder = new StringBuilder();
        for (TableColumn tableColumn : tableColumnList) {
            // 表单里没有id选项
            if (tableColumn.getColumnName().equalsIgnoreCase("id")) {
                continue;
            }
            // 排除deleted create_time  update_time 这个无需关注的字段
            if (tableColumn.getColumnName().equalsIgnoreCase("deleted") || tableColumn.getColumnName().equalsIgnoreCase("create_time")
                    || tableColumn.getColumnName().equalsIgnoreCase("update_time")) {
                continue;
            }
            // 动态生成 注意添加换行
            String column = SPACE8 + "<el-form-item prop=\"" + tableColumn.getColumnName() + "\" label=\"" + tableColumn.getColumnComment() + "\" >\n" +
                    SPACE8 + "  <el-input v-model=\"state.form." + tableColumn.getColumnName() + "\" autocomplete=\"off\" />\n" +
                    SPACE8 + "</el-form-item>\n";
            // 连接所有字符串
            builder.append(column);
        }
        return builder.toString();
    }

    private static String getLowerEntity(String tableName) {
        tableName = tableName.replaceAll("t_", "").replaceAll("sys_", "");
        // toCamelCase 方法 ：sys_user -> user;  user_rel -> userRel 把下划线转驼峰
        return StrUtil.toCamelCase(tableName);
    }

    private static String getEntity(String tableName) {
        String lowerEntity = getLowerEntity(tableName);
        // 把第一个字母变大写
        return lowerEntity.substring(0, 1).toUpperCase() + lowerEntity.substring(1);
    }

    private static DBProp getDBProp() {
        // 从 application.yml 取数据库连接信息
        ClassPathResource resource = new ClassPathResource("application.yml");
        YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
        yamlPropertiesFactoryBean.setResources(resource);
        Properties dbProp = yamlPropertiesFactoryBean.getObject();
        // return  yamlPropertiesFactoryBean.getObject();
        return DBProp.builder().url(dbProp.getProperty("spring.datasource.url")) // 字符串属性 不是对象属性
                .username(dbProp.getProperty("spring.datasource.username"))
                .password(dbProp.getProperty("spring.datasource.password")).build();
    }

    private static void generateJava (String tableName){
        DBProp dbProp = getDBProp();
        FastAutoGenerator.create(dbProp.getUrl(), dbProp.getUsername(), dbProp.getPassword())
                .globalConfig(builder -> {
                    builder.author(AUTHOR)//设置作者
                            .enableSwagger()
                            .disableOpenDir()
                            .outputDir(PROJECT_PATH + JAVA_CODE_PATH);//指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent(PACKAGE_NAME) // 设置父包名
                            .moduleName("") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, PROJECT_PATH + MAPPER_XML_PATH)); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.controllerBuilder().fileOverride().enableRestStyle().enableHyphenStyle()
                            .serviceBuilder().fileOverride()
                            .mapperBuilder().fileOverride()
                            .entityBuilder().fileOverride().enableLombok()
                            .addTableFills(new Column("create_time", FieldFill.INSERT));
                    builder.addInclude(tableName) // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .execute();
    }

}